# -*- coding: utf-8 -*-
# Gestión de packages de proyectos.

## vipera, un diseñador de aplicaciones para Python
##     Copyright (C) 2011 Ángel Luis García García
##
##    This program is free software: you can redistribute it and/or modify
##    it under the terms of the GNU General Public License as published by
##    the Free Software Foundation, either version 3 of the License, or
##    (at your option) any later version.
##
##    This program is distributed in the hope that it will be useful,
##    but WITHOUT ANY WARRANTY; without even the implied warranty of
##    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##    GNU General Public License for more details.
##
##    You should have received a copy of the GNU General Public License
##    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import wx

from packages_vista import dialogo_package, panel_packages
from i18n_vipera import t

class dialogo_package_p(dialogo_package):
    '''Diálogo para añadir módulo'''
    def __init__(self, parent, modulos, idioma = None):
        '''Constructor de clase'''
        dialogo_package.__init__(self, parent)
        # Idioma.
        self.SetTitle(t(u'Añadir módulo', idioma))
        self.m_comboBox_modulos.SetItems(modulos)
        
class panel_p(panel_packages):
    '''Panel principal de packages'''
    def __init__(self, parent, dato_packages = None, idioma = None):
        '''Constructor de clase'''
        # Llamamos al constructor del padre.
        panel_packages.__init__(self, parent)
        # Idioma.
        self.l = idioma
        # Cambiamos idioma de widgets generados con wxFB.
        self.m_button_add_file.SetToolTipString(t(u'Añadir módulo', self.l))
        self.m_button_package.SetToolTipString(t(u'Añadir directorio', self.l))
        self.m_button_eliminar.SetToolTipString(t(u'Eliminar módulo / directorio seleccionado', self.l))
        # Configuramos imágenes (iconos) de la jerarquía del árbol.
        isz = (16,16)
        il = wx.ImageList(isz[0], isz[1])
        self.fldridx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, isz))
        self.fldropenidx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER, isz))
        self.fileidx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, isz))
        self.m_treeCtrl_packages.SetImageList(il)
        self.il = il
        # Datos de packages a cargar.
        if dato_packages is not None: 
            self.__cargar_datos(dato_packages)

    def __cargar_datos(self, lista_packages):
        '''Carga de datos'''
        if lista_packages is None: return
        # Nombre del directorio raíz.
        nom_raiz = lista_packages[0][1].replace("/","")
        # Creamos nodo raíz.
        self.root = self.m_treeCtrl_packages.AddRoot(nom_raiz)
        # Definimos iconos para el root en estado normal y expandido.
        self.m_treeCtrl_packages.SetItemImage(self.root, self.fldridx, wx.TreeItemIcon_Normal)
        self.m_treeCtrl_packages.SetItemImage(self.root, self.fldropenidx, wx.TreeItemIcon_Expanded)
        # Reorganizamos lista de directorios y módulos, saltando el primer
        # elemento y recorriendo la lista en orden inverso, debido a cómo la 
        # hemos guardado.
        lista_aux = lista_packages[:0:-1]
        # Recorremos la lista de directorios, creando directorios y módulos.
        for i in lista_aux:
            # Empezamos el recorrido por el nodo raiz.
            nodo = self.root
            # Partimos la ruta en niveles.
            niveles = i[1].split("/")
            # Nueva lista, quitamos primer (raíz) y último (cadena vacía) elemento.
            nivel = niveles[1:len(niveles)-1]
            # Bandera de identificación de módulo.
            if i[0] == 'modulo': es_modulo = True
            else: es_modulo = False
            # Recorremos los nombres de los nodos.
            contador = 1
            for j in nivel:
                if not self.__existe_item(j,'directorio',nodo):
                    nodo_nuevo = self.m_treeCtrl_packages.AppendItem(nodo, j)
                    # Definimos iconos según sea directorio ó módulo.
                    if not es_modulo or contador < len(nivel):
                        self.m_treeCtrl_packages.SetItemImage(nodo_nuevo, self.fldridx, wx.TreeItemIcon_Normal)
                        self.m_treeCtrl_packages.SetItemImage(nodo_nuevo, self.fldropenidx, wx.TreeItemIcon_Expanded)
                    elif es_modulo and contador == len(nivel):
                        self.m_treeCtrl_packages.SetItemImage(nodo_nuevo, self.fileidx, wx.TreeItemIcon_Normal)
                    # Siguiente nodo.
                    nodo = nodo_nuevo
                else:
                    # Siguiente nivel.
                    nodo = self.m_treeCtrl_packages.GetLastChild(nodo)
                # Aumentamos el contador.
                contador += 1

    def OnCrearModulo(self, event):
        '''Manejador de eventos para creación de un módulo'''
        if self.m_treeCtrl_packages.GetCount() != 0: 
            # Si estamos en un directorio, creamos otro anidado.
            aux = self.pedir_datos('modulo')
            if aux is None or len(aux.strip()) == 0: return
            # ID del elemento seleccionado.
            id_sel = self.m_treeCtrl_packages.GetSelection()
            # [12-08-2011] Si no hay nada seleccionado, no se puede insertar nada.
            if id_sel.IsOk() == False:
                wx.MessageBox(t(u"Tiene que seleccionar un elemento del árbol", self.l),t(u"Atención", self.l),wx.OK)
                return -1
            # Si no estamos encima de un directorio nos vamos al padre.
            if self.m_treeCtrl_packages.GetItemImage(id_sel, wx.TreeItemIcon_Normal) == self.fileidx:
                # ID padre del elemento seleccionado.
                id_padre = self.m_treeCtrl_packages.GetItemParent(id_sel)
                id_sel = id_padre
            # Comprobamos que no haya módulos repetidos en el mismo nivel.
            if self.__existe_item(aux,'modulo', id_sel): return
            # Creamos el hijo.
            hijo = self.m_treeCtrl_packages.AppendItem(id_sel, aux)
            # Configuramos iconos.
            self.m_treeCtrl_packages.SetItemImage(hijo, self.fileidx, wx.TreeItemIcon_Normal)
        else:
            wx.MessageBox(t(u"Se debe de crear primero un directorio",self.l), t(u"Atención",self.l), wx.OK)
            
    def OnCrearDirectorio(self, event):
        '''Manejador de eventos para creación de un directorio'''
        # Si no hay nada, creamos el nodo padre.
        if self.m_treeCtrl_packages.GetCount() == 0: 
            aux = self.pedir_datos('root')
            if aux is None or len(aux.strip()) == 0: return
            # Creamos root.
            self.root = self.m_treeCtrl_packages.AddRoot(aux)
            # Definimos iconos para el root en estado normal y expandido.
            self.m_treeCtrl_packages.SetItemImage(self.root, self.fldridx, wx.TreeItemIcon_Normal)
            self.m_treeCtrl_packages.SetItemImage(self.root, self.fldropenidx, wx.TreeItemIcon_Expanded)
        else:
            # ID del elemento seleccionado.
            id_padre = self.m_treeCtrl_packages.GetSelection()
            # [12-08-2011] Si no hay nada seleccionado, no se puede insertar nada.
            if id_padre.IsOk() == False:
                wx.MessageBox(t(u"Tiene que seleccionar un elemento del árbol", self.l),t(u"Atención", self.l),wx.OK)
                return -1
            # Si no estamos encima de un directorio nos vamos a su padre.
            if self.m_treeCtrl_packages.GetItemImage(id_padre, wx.TreeItemIcon_Normal) == self.fileidx:
                # ID padre del elemento seleccionado.
                id_sel = self.m_treeCtrl_packages.GetItemParent(id_padre)
                id_padre = id_sel
            # Si estamos en un directorio, creamos otro anidado.
            aux = self.pedir_datos('directorio')
            if aux is None or len(aux.strip()) == 0: return
            # Comprobamos que no esté repetido el nombre del nodo.
            if self.__existe_item(aux,'directorio', id_padre): return
            # Incluimos nodo.
            hijo = self.m_treeCtrl_packages.AppendItem(id_padre, aux)
            # Configuramos iconos.
            self.m_treeCtrl_packages.SetItemImage(hijo, self.fldridx, wx.TreeItemIcon_Normal)
            self.m_treeCtrl_packages.SetItemImage(hijo, self.fldropenidx, wx.TreeItemIcon_Expanded)
        
    def pedir_datos(self, cadena):
        '''Pedir datos mediante un wx.TextEntryDialog.'''
        if cadena == 'modulo': cadena = t(u'Nombre del módulo nuevo: ', self.l)
        if cadena == 'directorio': cadena = t(u'Nombre del directorio nuevo: ', self.l)
        if cadena == 'root': cadena = t(u'Nombre del directorio padre: ', self.l)
        dialogo = wx.TextEntryDialog(self, cadena, 'Datos')
        dialogo.Show()
        if dialogo.ShowModal() == wx.ID_OK:
            ret = dialogo.GetValue()
            # No se puede incluir el carácter "/" ni "\".
            if ret.count("/") != 0 or ret.count("\\") != 0: ret = None
        else:
            # Botón cancelar. Nada que devolver.
            ret = None
        # Limpiamos memoria y nos vamos.
        dialogo.Destroy()
        return ret
    
    def __existe_item(self, nombre, tipo, nodo):
        '''Devuelve True si el nodo con nombre y tipo (directorio/modulo) pasado
        como parámetro existe, y False en caso contrario'''
        # Bajamos al último de los nodos hijos.
        nodo = self.m_treeCtrl_packages.GetLastChild(nodo)
        # Inicializamos centinela de búsqueda.
        encontrado = False
        # ¿Tiene hermanos anteriores el nodo actual?
        while True:
            # [12-08-2011] Si no existe el nodo, nos salimos.
            if nodo.IsOk() == False: break
            texto_nodo = self.m_treeCtrl_packages.GetItemText(nodo)
            # ¿No hay más nodos? Nos salimos.
            # if len(texto_nodo.strip()) == 0: break
            # ¿Se trata de un directorio ó de un módulo?
            if (tipo == 'directorio' and \
               self.m_treeCtrl_packages.GetItemImage(nodo, wx.TreeItemIcon_Normal) in [self.fldridx, self.fldropenidx]) \
               or (tipo == 'modulo' and \
               self.m_treeCtrl_packages.GetItemImage(nodo, wx.TreeItemIcon_Normal) == self.fileidx):
                # ¿Tiene el mismo nombre?
                if texto_nodo.strip() == nombre.strip():
                    encontrado = True
                    break
            # Nodo anterior.
            nodo = self.m_treeCtrl_packages.GetPrevSibling(nodo)
        # Devolvemos resultado de la búsqueda.
        return encontrado
    
    def __buscar_nodos(self, nodo, prefijo, resultados):
        '''Búsqueda recursiva de nodos'''
        # Creamos nombre de nodo con prefijo.
        nodo_nuevo = '%s%s%s' %(prefijo, self.m_treeCtrl_packages.GetItemText(nodo),'/')
        # Comprobamos si el nodo es un directorio ó un fichero.
        if self.m_treeCtrl_packages.GetItemImage(nodo, wx.TreeItemIcon_Normal) == self.fileidx:
            tipo = 'modulo'
        else:
            tipo = 'directorio'
        # Añadimos a lista de resultados la tupla (tipo, nombre de nodo).
        resultados.append((tipo,nodo_nuevo))
        # ¿Tiene hijos el nodo actual?
        if self.m_treeCtrl_packages.ItemHasChildren(nodo):
            # Buscamos por el último hijo.
            nodo_hijo = self.m_treeCtrl_packages.GetLastChild(nodo)
            self.__buscar_nodos(nodo_hijo, nodo_nuevo, resultados)
        # ¿Tiene hermanos el nodo actual?
        nodo_hermano = self.m_treeCtrl_packages.GetPrevSibling(nodo)
        # [12-08-2011] Si no existe el nodo, nos salimos.
        if nodo_hermano.IsOk() == True:
            texto_nodo = self.m_treeCtrl_packages.GetItemText(nodo_hermano)
            #if len(texto_nodo.strip()) != 0:
                # Buscamos por el hermano.
            self.__buscar_nodos(nodo_hermano, prefijo, resultados)
        # Devolvemos la lista de resultados.
        return resultados
  
    def OnEliminar(self, event):
        '''Elimina el nodo actual, así como sus descendientes'''
        if self.m_treeCtrl_packages.GetCount() != 0: 
            # ¿Eliminar?
            i = wx.MessageBox(t(u"¿Eliminar?", self.l),t(u"Atención", self.l),wx.YES_NO)
            if i != wx.YES: return
            # ID del elemento seleccionado.
            id_nodo = self.m_treeCtrl_packages.GetSelection()
            self.m_treeCtrl_packages.Delete(id_nodo)
        else:
            wx.MessageBox(t(u"No hay módulo o directorio a eliminar", self.l), t(u"Atención", self.l), wx.OK)
            
    def limpiar_widget(self):
        '''Método para limpiar todo el árbol'''
        self.m_treeCtrl_packages.DeleteAllItems()

    # #####################################################
    # Métodos para cargar/salvar estructura de directorios.
    # #####################################################
    
    def cargar_datos(self, lista_packages):
        '''Cargar estructura de directorios'''
        self.__cargar_datos(lista_packages)
        
    def salvar_datos(self):
        '''Salvar estructura de directorios'''
        nodo_actual = self.m_treeCtrl_packages.GetRootItem()
        if nodo_actual.IsOk() == False: return None
        ret = self.__buscar_nodos(nodo_actual, '', []) 
        return ret            
